<?php
namespace App\Common\Services;


use AlibabaCloud\Client\AlibabaCloud;
use AlibabaCloud\Client\Exception\ClientException;
use App\Common\Models\ComSmsModel;
use App\Exceptions\ApiException;
use App\Services\CommonBaseService;
use App\User\Models\UserInfoModel;
use Illuminate\Database\QueryException;
use Illuminate\Support\Facades\Cache;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail;

class ComSmsService extends CommonBaseService
{
    protected $cache = true;

    protected $cacheBucket = 'ComSms:';

    protected $tokenBucket = 'Token:';

    protected $activeBucket = "Active:";

    /**
     * 发送短信验证码
     * @param string $phone
     * @param string $accessKeyId
     * @param string $accessKeySecret
     * @param string $signName
     * @param string $templateCode
     * @param string $type
     * @return bool|mixed
     * @throws \App\Exceptions\ApiException
     * @throws ClientException
     */
    public function sendSMSInfo($smsParams,$accessKeyId = '', $accessKeySecret = '', $signName = '', $templateCode = '' )
    {
        $phone=$smsParams['phone'];
        if(isset($smsParams['is_send'])){
            $isSend=$smsParams['is_send'];
        }else{
            $isSend=1;
        }
        $appCode=empty($smsParams['app_code'])?'':$smsParams['app_code'];
        $countryCode=empty($smsParams['country_code'])?'86':$smsParams['country_code'];
        $ret=['code'=>0,'data'=>[],'message'=>''];
        try {
            $code = mt_rand(100000, 999999);
            if($isSend){
                //发送短信

                if (!empty($countryCode) && $countryCode != 86) {
                    if (empty($accessKeyId)) {
                        $accessKeyId = config('sms.foreign_access_key_id'); //阿里云短信公钥
                    }
                    if (empty($accessKeySecret)) {
                        $accessKeySecret = config('sms.foreign_access_key_secret'); //阿里云短信私钥
                    }
                    if (empty($signName)) {
                        $signName = config('sms.foreign_sign_name'); //阿里云短信 签名名称
                    }
                    if (empty($templateCode)) {
                        $templateCode = config('sms.foreign_template_code'); //阿里云短信 短信模板ID
                    }
                }else{
                    if (empty($accessKeyId)) {
                        $accessKeyId = config('sms.access_key_id'); //阿里云短信公钥
                    }
                    if (empty($accessKeySecret)) {
                        $accessKeySecret = config('sms.access_key_secret'); //阿里云短信私钥
                    }
                    if (empty($signName)) {
                        $signName = config('sms.sign_name'); //阿里云短信 签名名称
                        $appSignName=config('sms.app_sign_name');
                        if($appSignName&&!empty($appCode)){
                            if(!empty($appSignName[$appCode])) {
                                $signName=$appSignName[$appCode];
                            }
                        }
                    }
                    if (empty($templateCode)) {
                        $templateCode = config('sms.template_code'); //阿里云短信 短信模板ID
                    }
                }

                AlibabaCloud::accessKeyClient($accessKeyId, $accessKeySecret)
                    ->regionId('cn-hangzhou')// replace regionId as you need
                    ->asDefaultClient();
                $response = AlibabaCloud::rpc()
                    ->product('Dysmsapi')
                    // ->scheme('https') // https | http
                    ->version('2017-05-25')
                    ->action('SendSms')
                    ->method('POST')
                    ->host('dysmsapi.aliyuncs.com')
                    ->options([
                        'query' => [
                            'SignName' => $signName, //阿里云短信 签名名称
                            'TemplateCode' => $templateCode, //阿里云短信 短信模板ID
                            'PhoneNumbers' => $phone, //手机号
                            'TemplateParam' => '{"code":' . $code . '}',//验证码参数  json格式
                        ],
                    ])
                    ->request();
                $data = [
                    'phone' => $phone,
                    'code' => $code,
                    'template_code' => $templateCode,
                    'error' => empty($params['error']) ? '' : $params['error'],
                    'type' => 0
                ];
                $responseData= $response->toArray();
                if (isset($responseData['Code']) && $responseData['Code'] == 'OK') {
                    $currentTime = time(); //当前时间
                    $data['status'] = 1;
                    $data['expire_time']=$currentTime + config('sms.expireTime');
                    $key=$phone;
                    $cacheKey=md5($key);
                    $cacheTime=config('cache.sms_time');
                    $this->setCacheData($cacheKey,$data,$cacheTime);
                    $result = $this->updatePhoneCode($data);
                    $resultData['id']=$result;
                    $resultData['code']=$code;
                    $resultData['phone']=$phone;
                    $ret['data'] = $resultData;
                    return $ret;
                } else {
                    $data['status'] = -1;
                    $errorMessage = empty($response->Message) ? '' : $response->Message;
                    $errorCode = empty($response->Code) ? '' : $response->Code;
                    $errorRequestId = empty($response->RequestId) ? '' : $response->RequestId;
                    $data['error'] = 'ErrorRequestId' . $errorRequestId . ';ErrorCode:' . $errorCode . ';Message:' . $errorMessage;
                    Log::info('method:error:' . $response);
                    // throw new ApiException(1001); //短信发送参数code错误
                    $ret['code']=1010;
                    return $ret;
                }
            }else{
                $data = [
                    'phone' => $phone,
                    'code' => $code,
                    'template_code' => '',
                    'error' => '',
                    'type' => 0
                ];
                $currentTime = time(); //当前时间
                $data['status'] = 1;
                $data['expire_time']=$currentTime + config('sms.expireTime');
                $key=$phone;
                $cacheKey=md5($key);
                $cacheTime=config('cache.sms_time');
                $this->setCacheData($cacheKey,$data,$cacheTime);
                $result = $this->updatePhoneCode($data);
                $resultData['id']=is_array($result)?0:$result;
                $resultData['code']=$code;
                $resultData['phone']=$phone;
                $ret['data'] = $resultData;
                return $ret;
            }

        } catch (\Exception $ex) {
            Log::info('method:sendSMSInfo:' . $ex->getMessage());
            Log::info('method:sendSMSInfo:' . $ex->getTraceAsString());
            $ret['code']=1004;
            $ret['message']=$ex->getMessage();
            return $ret;
            // throw new ApiException(500); //短信发送参数错误
        }
    }


    /**
     * 短信记录
     * @param array $params 短信存储参数
     * @return bool|mixed
     * @throws \App\Exceptions\ApiException
     */
    public function updatePhoneCode($params = [])
    {
        //手机验证码信息
        $codeData = [
            'phone' => $params['phone'],
            'code' => $params['code'],
            'template_code' => $params['template_code'],
            'status' => $params['status'],
            'error' => empty($params['error']) ? '' : $params['error'],
            'type' => empty($params['type']) ? 0 : $params['type'],
            'create_time' => nowTime()
        ];
        if(!empty($params['expire_time'])){
            $codeData['expire_time']= date('Y-m-d H:i:s', $params['expire_time']);
        }
        try {
            $result=$this->model->insertGetId($codeData);
            if (!$result) {
                Log::info('method:updatePhoneCode:保存验证码失败');
                $ret['code']=1004;
                $ret['message']= '保存验证码失败';
                return $ret;
            }
            return $result;
        } catch (QueryException $ex) {
            //异常处理
            Log::info('method:updatePhoneCode:' . $ex->getMessage());
            Log::info('method:updatePhoneCode:' . $ex->getTraceAsString());
            $ret['code']=1004;
            $ret['message']=$ex->getMessage();
            return $ret;
        }
    }

    /**
     * 校验短信验证码是否有效
     * @param string $phone 手机号
     * @param string $code 短信验证码
     * @return array  -1 失败重新获取验证码 -2验证码错误重新输入，1 成功是否验证成功
     */
    public  function validateCode($phone, $code)
    {
        //todo 通过redis 缓存来验证
        $result=['code'=>-1];
        $current_time = time();
        $key=$phone;
        $cacheKey=md5($key);
        $cacheData=$this->getCacheData($cacheKey);
        if($cacheData){
            if(!empty($cacheData['expire_time'])&&$cacheData['expire_time']>$current_time&&$code==$cacheData['code']){
                $result['code']=1;
                $this->removeByKey($cacheKey);
            }else if($code!=$cacheData['code']){
                $result['code']=-2;
            }
        }
        return $result;
    }

    /**
     * 校验短信验证码一分钟内是否重复发送
     * */
    public function validataPhoneMinute($phone,$type){
        $result=['code'=>0];
        $where=[
            'phone' => $phone,
            'type' => $type,
            'status' => 1,
        ];
        $expireTime = date("Y-m-d H:i:s",strtotime("+4 minute",strtotime(nowTime()))); // 短信有效时间为5分钟。当前时间添加4分钟
        $smsData = $this->model->where($where)->where('expire_time','>',$expireTime)->first();
        if(!empty($smsData)){
            $result['code']=-1;
        }
        return $result;
    }

    /**
     * 通用缓存方法
     * @param string $key
     * @param array $data
     * */
    public function setCacheData($key, $data,$cacheTime=0)
    {
        $cacheTime=empty($cacheTime)?config('cache.def_time'):$cacheTime;
        Cache::put($this->getCacheKey($key), $data, $cacheTime);
    }


    /**
     * 获取通用缓存数据key
     * @param string $key
     * @return string
     * */
    private function getCacheKey($key)
    {
        $prefix='VERIFICATION';
        return $this->cacheBucket.$prefix.$key;
    }

    /**
     * 通用缓存方法
     * @param string $key
     * @param array $data
     * */
    public function getCacheData($key)
    {
        $dataKey= $this->getCacheKey($key);
        return Cache::get($dataKey);
    }
}
